package com.wasion.gydpe.common.security;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.AntUrlPathMatcher;
import org.springframework.security.web.util.UrlMatcher;

import com.wasion.gydpe.dao.PermissionDao;
import com.wasion.gydpe.dao.ResourceDao;
import com.wasion.gydpe.exception.DataAccessException;
import com.wasion.gydpe.model.Permission;

/**
 * 
 * @ClassName: LocalInvocationSecurityMetadataSource
 * @Description: 从数据库提取权限和资源，装配到HashMap中，供Spring Security使用，用于权限校验
 * @author 高意
 * @date Oct 15, 2012 3:07:13 PM
 * 
 */
public class LocalInvocationSecurityMetadataSource implements
		FilterInvocationSecurityMetadataSource {

	private UrlMatcher urlMatcher = new AntUrlPathMatcher();

	private static Map<String, Collection<ConfigAttribute>> resourceMap = null;

	private PermissionDao permissionDao;

	private ResourceDao resourceDao;

	/**
	 * 
	 * Description: 构造方法，依赖的数据访问接口必须采用构造方法注入，并且XML进行配置（不能用注解方式）
	 * 
	 * @param permissionDao
	 * @param resourceDao
	 * @throws DataAccessException
	 */
	public LocalInvocationSecurityMetadataSource(PermissionDao permissionDao,
			ResourceDao resourceDao) throws DataAccessException {

		this.permissionDao = permissionDao;
		this.resourceDao = resourceDao;

		loadResourceDefine();
	}

	/**
	 * 
	 * @Title: loadResourceDefine
	 * @Description: 装载资源
	 * @param
	 * @return
	 * @throws
	 */
	private void loadResourceDefine() throws DataAccessException {

		// 在Web服务器启动时，提取系统中的所有权限
		List<Permission> list = permissionDao.query();

		/*
		 * 应当是资源为key， 权限为value。 资源通常为url， 权限就是那些以ROLE_为前缀的角色。 一个资源可以由多个权限来访问。
		 */
		resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
		for (Permission p : list) {

			String auth = p.getId() + "";
			ConfigAttribute ca = new SecurityConfig(auth);

			Map<String, Object> param = new HashMap<String, Object>();
			param.put("permissionId", auth);

			List<com.wasion.gydpe.model.Resource> resList = resourceDao
					.query(param);

			for (com.wasion.gydpe.model.Resource res : resList) {

				String url = res.getRsUrl();

				/*
				 * 判断资源文件和权限的对应关系，如果已经存在相关的资源url，则要通过该url为key提取出权限集合，将权限增加到权限集合中。
				 */
				if (resourceMap.containsKey(url)) {
					Collection<ConfigAttribute> value = resourceMap.get(url);
					value.add(ca);
					resourceMap.put(url, value);
				} else {
					Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();
					atts.add(ca);
					resourceMap.put(url, atts);
				}
			}
		}
	}

	/**
	 * 
	 * @Title: getAttributes
	 * @Description: 根据URL，找到相关的权限配置
	 * @param
	 * @return
	 * @throws
	 */
	public Collection<ConfigAttribute> getAttributes(Object object)
			throws IllegalArgumentException {

		// object 是一个URL，被用户请求的url
		String url = ((FilterInvocation) object).getRequestUrl();

		/***********************************************************************
		 * int firstQuestionMarkIndex = url.indexOf("?"); if
		 * (firstQuestionMarkIndex != -1) { url = url.substring(0,
		 * firstQuestionMarkIndex); }
		 **********************************************************************/

		Iterator<String> ite = resourceMap.keySet().iterator();
		while (ite.hasNext()) {
			String resURL = ite.next();
			if (urlMatcher.pathMatchesUrl(url, resURL)) {
				return resourceMap.get(resURL);
			}
		}
		return null;
	}

	public boolean supports(Class<?> clazz) {
		return true;
	}

	public Collection<ConfigAttribute> getAllConfigAttributes() {
		return null;
	}
}
